package com.zwps.biz.domain.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zwps.biz.api.model.vo.heating.RealTimeHeatingVO;
import com.zwps.biz.api.model.vo.heating.SelectHeatingLocalsVO;
import com.zwps.biz.api.model.vo.heating.SelectHeatingTokenVO;
import com.zwps.biz.dal.db.dao.RealTimeHeatingDAO;
import com.zwps.biz.dal.db.object.RealTimeHeatingDO;
import com.zwps.biz.domain.converter.RealTimeHeatingConverter;
import com.zwps.biz.domain.service.RealTimeHeatingService;
import com.zwps.common.core.exception.UserActionException;
import com.zwps.common.minio.service.MinioService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
@Slf4j
public class RealTimeHeatingServiceImpl implements RealTimeHeatingService {

    @Value("${application.auth.real-time-heating-host}")
    private String realTimeHeatingHost;

    @Value("${application.auth.real-time-heating-user}")
    private String realTimeHeatingUser;

    @Value("${application.auth.real-time-heating-key}")
    private String realTimeHeatingKey;

    @Value("${application.auth.real-time-heating-local-id}")
    private Integer localId;

    @Autowired
    private MinioService minioService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RealTimeHeatingDAO realTimeHeatingDAO;

    private String tokenPrefix = "Bearer ";

    final int timeout = 30000;

    @Override
    public String getToken() {
        Map<String, Object> params = new HashMap<>();
        params.put("username", realTimeHeatingUser);
        params.put("apikey", realTimeHeatingKey);
        HttpRequest request = HttpUtil.createGet(realTimeHeatingHost + "/api/v2/authorization/user")
                .form(params)
                .header("accept", ContentType.JSON.getValue()).timeout(timeout);
        try(HttpResponse response =  request.execute()) {
            log.info("/api/v2/authorization/user 请求返回 {}", response.body());
            SelectHeatingTokenVO selectHeatingTokenVO = objectMapper.readValue(response.body(), SelectHeatingTokenVO.class);
            return selectHeatingTokenVO.getToken();
        } catch (Exception error) {
            log.info("/api/v2/authorization/user 请求报错 {}", error.getMessage());
            throw new UserActionException("查询失败 " +  error.getMessage());
        }
    }

    @Override
    public List<SelectHeatingLocalsVO> getLocals(String token) {
        HttpRequest requestLocals = HttpUtil.createGet(realTimeHeatingHost + "/api/v2/config/locals")
                .header("accept", ContentType.JSON.getValue())
                .header("authorization", token)
                .timeout(timeout);
        try(HttpResponse responseLocals =  requestLocals.execute()) {
            log.info("/api/v2/config/locals 请求返回 {}", responseLocals.body());
            List<SelectHeatingLocalsVO> localsList = objectMapper.readValue(responseLocals.body(), new TypeReference<List<SelectHeatingLocalsVO>>() {});
//            if(localsList.size() > 0) {
//                localId = localsList.get(0).getId();
//            } else {
//                throw new UserActionException("地区获取错误");
//            }
            return localsList;
        } catch (Exception error) {
            log.info("/api/v2/config/locals 请求报错 {}", error.getMessage());
            throw new UserActionException("查询失败" +  error.getMessage());
        }
    }
    @Override
    public void updatePopulationsLocalStatistics(String token, Integer localId, String currentDate) {
        MD5 md5 = new MD5();
        String populationsUri = "/api/v2/populations/localstatistics/" + localId + "/" + currentDate;
        HashMap<String, Object> params = new HashMap<>();
        params.put("top", 10);
        params.put("district_type", 3);
        params.put("is_ratio", 1);
        HttpRequest requestPopulations = HttpUtil.createGet(realTimeHeatingHost + populationsUri)
                .header("accept", ContentType.JSON.getValue())
                .header("authorization", token)
                .timeout(timeout)
                .form(params);
        RealTimeHeatingDO realTimeHeatingDO = new RealTimeHeatingDO();
        try(HttpResponse responsePopulations =  requestPopulations.execute()) {
            log.info("{} 请求返回 {}", populationsUri, responsePopulations.body());
            Map<String, Object> result = objectMapper.readValue(responsePopulations.body(), new TypeReference<Map<String, Object>>() {});
            if((int) result.get("Code") != 401) {
                ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(responsePopulations.body().getBytes());
                String fileName = md5.digestHex("localstatistics_" + currentDate) + ".json";
                String filePath = minioService.upload(byteArrayInputStream, currentDate.substring(0, 8), fileName);
                LocalDateTime localDateTime = LocalDateTime.now();
                String createTime = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                realTimeHeatingDO.setCreateTime(DateUtil.parse(createTime));
                realTimeHeatingDO.setFindTime(DateUtil.parse(currentDate + "00"));
                realTimeHeatingDO.setFilePath(filePath);
                realTimeHeatingDO.setFileName(fileName);
                realTimeHeatingDO.setType(1);
                realTimeHeatingDAO.insert(realTimeHeatingDO);
            } else {
                throw new UserActionException("查询失败：" + result.get("Message"));
            }
        } catch (Exception error) {
            throw new UserActionException("查询失败：" + populationsUri +  error.getMessage());
        }
    }

    @Override
    public void updatePopulationsHotmap(String token, Integer localId, String currentDate) {
        MD5 md5 = new MD5();
        String hotMapUri = "/api/v2/populations/localstatisticsforhotmap/" + localId + "/" + currentDate;
        RealTimeHeatingDO realTimeHeatingDO = new RealTimeHeatingDO();
        HashMap<String, Object> params = new HashMap<>();
        params.put("limit", 500);
        params.put("offset", 0);
        params.put("type", 1);
        params.put("is_ratio", 1);
        HttpRequest requestHotMap = HttpUtil.createGet(realTimeHeatingHost + hotMapUri)
                .header("accept", ContentType.JSON.getValue())
                .header("authorization", token)
                .timeout(timeout)
                .form(params);
        try(HttpResponse responseHotMap =  requestHotMap.execute()) {
            log.info("{} 请求返回 {}", hotMapUri, responseHotMap.body());
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(responseHotMap.body().getBytes());
            String fileName = md5.digestHex("localstatisticsforhotmap_" + currentDate) + ".json";
            String filePath = minioService.upload(byteArrayInputStream, currentDate.substring(0, 8), fileName);
            LocalDateTime localDateTime = LocalDateTime.now();
            String createTime = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            realTimeHeatingDO.setCreateTime(DateUtil.parse(createTime));
            realTimeHeatingDO.setFindTime(DateUtil.parse(currentDate + "00"));
            realTimeHeatingDO.setFilePath(filePath);
            realTimeHeatingDO.setFileName(fileName);
            realTimeHeatingDO.setType(2);
            realTimeHeatingDAO.insert(realTimeHeatingDO);
        } catch (Exception error) {
            throw new UserActionException("查询失败" + hotMapUri +  error.getMessage());
        }
    }

    @Override
    public RealTimeHeatingVO getPopulationsLocalStatistics(Integer type) {
        LambdaQueryWrapper<RealTimeHeatingDO> query = Wrappers.lambdaQuery(RealTimeHeatingDO.class).eq(RealTimeHeatingDO::getType, type).orderBy(true, false, RealTimeHeatingDO::getCreateTime).last("LIMIT 1");
        RealTimeHeatingDO realTimeHeatingDO = realTimeHeatingDAO.selectOne(query);
        return RealTimeHeatingConverter.INSTANCE.toRealTimeHeatingVO(realTimeHeatingDO);
    }

    @Override
  //  @Scheduled(cron = "0 0/10 * * * ?")
    public void realTimeHeatingScheduled() {
        System.out.println("定时任务开始 -------------------------------》");
        LocalDateTime localDateTime = LocalDateTime.now();
        // 向下取整最近的整数分钟
        Integer minute = roundTo(localDateTime.getMinute(), 10);
        // 往前推40分钟
        localDateTime = localDateTime.withMinute(minute).minusMinutes(40);

        RealTimeHeatingDO realTimeHeatingDO = realTimeHeatingDAO.selectOne(Wrappers.<RealTimeHeatingDO>lambdaQuery().orderBy(true, false, RealTimeHeatingDO::getCreateTime).last("LIMIT 1"));
        if(realTimeHeatingDO != null) {
            LocalDateTime findTime = realTimeHeatingDO.getFindTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
            Boolean isBefore = findTime.isBefore(localDateTime);

            // 如果最新一条数据的生产时间不在需要插入的时间之前则返回
            if(!isBefore) return;
        }
        String currentDate = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
        String token = getToken();

        if(StrUtil.isNotEmpty(token)) {
            token = tokenPrefix + token;
            updatePopulationsLocalStatistics(token, localId, currentDate);
            updatePopulationsHotmap(token, localId, currentDate);
        } else {
            throw new UserActionException("token获取失败");
        }
    }

    private static Integer roundTo(Integer param, Integer fi) {
        int remainder = param%fi;
        if(remainder == 0) {
            return param;
        } else if(remainder < fi/2) {
            return param/fi*fi;
        } else {
            return param/fi*fi + fi;
        }
    }

    public static void main(String[] args) {

    }
}
